package org.qloudgen.txn.dilithium.cluster.common;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.qloudgen.txn.dilithium.cluster.beans.Cluster;
import org.qloudgen.txn.dilithium.cluster.beans.ParameterBean;
import org.qloudgen.txn.dilithium.cluster.beans.PgxcConfProp;

public class ShellExec {

	static Log log = LogFactory.getLog(ShellExec.class);
	
	public static void checkCreateSysuserLocal(){
		
		String[] check_superuser_command =
			{"sh", CommonValues.CHECK_SUPERUSER_SH, CommonValues.SYSUSER};
        int ret = ExecShellCommand.execShellCommandWithReturn(check_superuser_command);
		
        if (ret == 0 ) {
	        String[] create_superuser_command =
	            {"sh", CommonValues.CREATE_SUPERUSER_SH, CommonValues.SYSUSER, CommonValues.SYSUSER_PASSWORD_LOCAL};
	        ExecShellCommand.execShellCommandWithReturn(create_superuser_command);
	        
	        if (ret != 0 ) {
		        log.error(" error in check and create sysuser locally. ");
	        }

        } else {
        	log.info(" sysuser exists locally. ");
        }
       
	String[] construct_isa_command =
                                {"sh", CommonValues.CONSTRUCT_ISA_LOCAL, CommonValues.SYSUSER};
                ret = ExecShellCommand.execShellCommandWithReturn(construct_isa_command);

                if (ret != 0 ) {
                        log.error(" error in constructing isa local. ");
                } else {
                        log.info(" success in constructing isa local.");
                }
 
	}
	
	public static int clusterOperator(Cluster cluster,String operatorType, String nodeIp,  String logFile){
		
		int ret = 0;
		
	    if (operatorType.equals(CommonValues.CLUSTER_ADD_NODE)
				||operatorType.equals(CommonValues.CLUSTER_REMOVE_NODE)
				||operatorType.equals(CommonValues.CLUSTER_ADD_CLIENT)
				||operatorType.equals(CommonValues.CLUSTER_REMOVE_CLIENT)){
		
			/* add/remove node */
	    	String[] command = {"sh", CommonValues.OPERATOR_SH,cluster.getControllerIp(),CommonValues.SYSUSER, 
	    			CommonValues.getConfigFileName(cluster.getClusterID()),operatorType , nodeIp};
	    	ret = ExecShellCommand.execShellCommandWithPrintLogToWeb( command,logFile);
			
		} else if (operatorType.equals(CommonValues.CLUSTER_START)
				||operatorType.equals(CommonValues.CLUSTER_STOP)){
		
			//start/stop cluster
			String[] command = {"sh", CommonValues.OPERATOR_SH,cluster.getControllerIp(),CommonValues.SYSUSER, 
	    			CommonValues.getConfigFileName(cluster.getClusterID()),operatorType };
			ret = ExecShellCommand.execShellCommandWithReturn( command );
			
		}

		return ret;
	}
	
	public static void logToWeb(String logFile, StringBuffer sb, boolean thread_is_runnable){
		StringBuffer sb1 = new StringBuffer();
   	 	String[] command_org = {"sh", "-c", "tail -f " + logFile};
        List<String> command = new ArrayList<String>();
        for (int i = 0; i < command_org.length; i++) {
            command.add(command_org[i]);
        }

        ProcessBuilder process_builder = new ProcessBuilder(command);
        process_builder.redirectErrorStream(true);
        InputStreamReader input_stream_reader = null;
        Process process = null;
        int index = 0 , line = 0 , line_limit = 25;
        sb.setLength(0);
        
        try {
            process = process_builder.start();
            input_stream_reader =
                    new InputStreamReader(
                            process.getInputStream(), "UTF-8");
            } catch (Exception e) { }
        while (true) {
            try {
           	 int c = input_stream_reader.read();
                if (c == -1) {
                    input_stream_reader.close();
                    break;
                }
                sb1.append(String.valueOf((char) c));
                if (String.valueOf((char) c).equals("\n")){
                    sb.append(sb1.toString());
                    sb1.setLength(0);
                    line++;
                }
                
                if (line > line_limit && String.valueOf((char) c).equals("\n")) {
                	index = StringUtils.indexOf(sb.toString(), "\n") + 1;
                	sb.delete(0, index);
                }
                
            } catch (Exception e) { }
            if (!thread_is_runnable) {
                break;
            }
        }
        return;
	}
	
	public static int createLogFile(String logFile){
		
		String[] command =
			{"sh", CommonValues.CREATE_LOG_FILE_SH, CommonValues.SYSUSER, CommonValues.LOGDIR,logFile};
        int ret = ExecShellCommand.execShellCommandWithReturn(command);
		
        return ret;
	}

	public static int getMonitorInfo(Cluster cluster,StringBuffer monitorInfo) {
		
		String[] command = {"sh",
				CommonValues.OPERATOR_SH,cluster.getControllerIp(),CommonValues.SYSUSER, 
    			CommonValues.getConfigFileName(cluster.getClusterID()),CommonValues.CLUSTER_MONITOR };
		int ret = ExecShellCommand.execShellCommandWithReturnLog( command, monitorInfo);
        
		return ret;
	}

   public static int generateSSHKey(String nodeIp,String sysUser,String sysUserPassword){
		
		String[] command =
			{"sh", CommonValues.GENERATE_SSHKEY_SH, nodeIp,sysUser,sysUserPassword};
      int ret = ExecShellCommand.execShellCommandWithReturn(command);
      
      return ret;
  }
   
   public static int copySSHKey(String flag,String fromIp,String toIp,String sysUser,String sysUserPassword){
		
	   String[] command =
			{"sh", CommonValues.COPY_SSHKEY_SH, flag, (fromIp == null)?"default":fromIp,toIp,sysUser,sysUserPassword};
       int ret = ExecShellCommand.execShellCommandWithReturn(command);
       
       return ret;
   }

   public static int initCluster(Cluster cluster, String nodeIp, String logFile) {
	   
	  String[] command =
			{"sh", CommonValues.INIT_CLUSTER_SH, CommonValues.getConfigFileName(cluster.getClusterID()), 
			   cluster.getControllerIp(),cluster.getGtmMasterIp(),nodeIp, cluster.getSysUser()};
      int ret = ExecShellCommand.execShellCommandWithPrintLogToWeb(command,logFile);
      
      return ret;
   }

   public static int createParameterFiles(Cluster cluster,ArrayList<ParameterBean> paramList,StringBuffer sb, String logFile) {
	   
	  /* createParameterFiles local */
	  PgxcConfProp coordProps = new PgxcConfProp();
	  PgxcConfProp datanodeProps = new PgxcConfProp();
	  
	  for (ParameterBean parameter:paramList){
		  
		  String value = String.valueOf(parameter.getParamValue());
		  
		  if (CommonValues.paramUnits.containsKey(parameter.getParamName()))
			  value = value + CommonValues.paramUnits.get(parameter.getParamName());
			  
		  if (parameter.getParamType().equals(CommonValues.COORDINATOR_PARAM)) 
			  coordProps.put(parameter.getParamName(), value);
		  else if (parameter.getParamType().equals(CommonValues.DATANODE_PARAM)) 
			  datanodeProps.put(parameter.getParamName(), value);	  
	  }
	  
	  /* parameter file names */
	  String coordFile = CommonValues.PGXC_SYSUSER_HOME+"/"+CommonValues.COORD_EXTRA_CONFIG+"_"+String.valueOf(cluster.getClusterID());
	  String datanodeFile = CommonValues.PGXC_SYSUSER_HOME+"/"+CommonValues.DATANODE_EXTRA_CONFIG+"_"+String.valueOf(cluster.getClusterID());
	  
	  String newCoordFile = CommonValues.PGXC_SYSUSER_HOME+"/"+CommonValues.PGXC_SHELL_DIR+"/"+CommonValues.COORD_EXTRA_CONFIG;
	  String newDatanodeFile = CommonValues.PGXC_SYSUSER_HOME+"/"+CommonValues.PGXC_SHELL_DIR+"/"+CommonValues.DATANODE_EXTRA_CONFIG;
	  
	  writeFile(coordFile,coordProps,sb);
	  writeFile(datanodeFile,datanodeProps,sb);
	  
	  /* scp to controller node */
	  int ret = scpFile(cluster,coordFile,newCoordFile,logFile);
	  ret = scpFile(cluster,datanodeFile,newDatanodeFile,logFile);
	  
      return ret;
      
   }
   
   public static int scpFile(Cluster cluster, String file, String newFile, String logFile) {
	   
	  String[] command =
			{"sh", CommonValues.SCP_FILE_SH, cluster.getControllerIp(),CommonValues.SYSUSER,file,newFile};
	  
	  int ret = 0;
	  if (logFile == null)
		  ret = ExecShellCommand.execShellCommandWithReturn(command);
	  else 
		  ret = ExecShellCommand.execShellCommandWithPrintLogToWeb(command,logFile);
	  
      return ret;
   }
   
   public static int scpFile(Cluster cluster, String file, String newFile) {
	   
	  return scpFile(cluster,file,newFile,null);
	  
   }
   
   public static void writeFile(String fileName, Properties prop ,StringBuffer sb){
		
		File file = new File(fileName);
        PrintWriter print_writer;
		try {
			print_writer = new PrintWriter(new BufferedWriter(
			        new FileWriter(file, true)));
	        print_writer.println(prop.toString());
	        print_writer.close();
		} catch (IOException e) {
			e.printStackTrace();
			sb.insert(0, CommonValues.ERROR_FILE + "\n");
			return;
		}
	}

    public static int resetDBSuperUserPassword(Cluster cluster) {
    	String[] command =
			{"sh", CommonValues.RESET_DBSUPERUSER_PASSWORD_SH,  
			   cluster.getControllerIp(),cluster.getNodeIpsList().get(0),cluster.getSysUser(),cluster.getDBSuperuserPassword()};
        int ret = ExecShellCommand.execShellCommandWithReturn(command);
      
        return ret;
	}
}
